﻿using Mozhi.Abp.Domain.BasicData;
using mozhi.smarterp.Finance.Enums;
using System;
using System.Collections.Generic;
using Volo.Abp;
using System.Linq;

namespace mozhi.smarterp.Finance.Treasuries
{
    /// <summary>
    /// 付款申请
    /// </summary>
    public class PaymentRequisition : DocumentAggregateRoot
    {
        public PaymentRequisitionType Type { private set; get; }

        public TradingPartnerType TradingPartnerType { private set; get; }

        public Guid? SupplierId { private set; get; }

        public Supplier Supplier { private set; get; }

        public Guid? EmployeeId { private set; get; }

        public Employee Employee { private set; get; }

        public Guid? CustomerId { private set; get; }

        public Customer Customer { private set; get; }

        public Guid CurrencyId { private set; get; }

        public Currency Currency { private set; get; }

        public decimal ExchangeRate { private set; get; }

        /// <summary>
        /// 应付金额
        /// </summary>
        public decimal Amount { private set; get; }

        /// <summary>
        /// 应付金额原币
        /// </summary>
        public decimal AmountFr { private set; get; }

        /// <summary>
        /// 付款金额
        /// </summary>
        public decimal? PaymentAmount { private set; get; }

        /// <summary>
        /// 付款金额原币
        /// </summary>
        public decimal? PaymentAmountFr { private set; get; }

        /// <summary>
        /// 是否预付款
        /// </summary>
        public bool IsAdvanced { private set; get; }

        public List<PaymentRequisitionItem> Items { private set; get; }

        private PaymentRequisition() { }

        public PaymentRequisition(Guid id, string number, DateTime date, PaymentRequisitionType type, TradingPartnerType tradingPartnerType, Supplier supplier, Employee employee, Customer customer, Currency currency,
            decimal exchangeRate, bool isAdvanced, DocumentStatusType status, string comment)
        {
            Id = id;

            Number = number;
            Date = date;

            Type = type;
            TradingPartnerType = tradingPartnerType;
            Supplier = supplier;
            SupplierId = Supplier?.Id;

            Employee = employee;
            EmployeeId = Employee?.Id;

            Customer = customer;
            CustomerId = Customer?.Id;

            Currency = currency;
            CurrencyId = Currency == null ? default : Currency.Id;

            ExchangeRate = exchangeRate;

            IsAdvanced = isAdvanced;

            SetStatus(status);
            Comment = comment;

            Items = new List<PaymentRequisitionItem>();

            Validate();
        }

        public void Change(DateTime date,decimal exchangeRate, DocumentStatusType status, string comment)
        {
            Date = date;
            ExchangeRate = exchangeRate;

            SetStatus(status);
            Comment = comment;

            Validate();
        }


        public void SetItems(List<PaymentRequisitionItem> items)
        {
            ValidateStatus();

            foreach (var item in items)
            {
                var match = Items.FirstOrDefault(x => x.Id == item.Id);

                if (match != null)
                    Items.Remove(match);

                Items.Add(item);
            }

            var ids = items.Select(x => x.Id).ToList();

            var removedItems = Items.Where(x => !ids.Contains(x.Id)).ToList();

            foreach (var item in removedItems)
            {
                Items.Remove(item);
            }

            if (Items.Count == 0)
                throw new UserFriendlyException("付款申请单明细不能为空", "100000");

            CalculateAmount();
        }

        #region
        private void Validate()
        {
            if (Number.IsNullOrEmpty())
                throw new UserFriendlyException("编号不能为空", "100000");

            if (CurrencyId == default)
                throw new UserFriendlyException("币别不能为空", "100000");

            if (ExchangeRate <= 0)
                throw new UserFriendlyException("汇率必须大于0", "100000");

            if (Date == default)
                throw new UserFriendlyException("币别不能为空", "100000");

            if (!SupplierId.HasValue && !EmployeeId.HasValue && !CustomerId.HasValue)
                throw new UserFriendlyException("交易对象不能为空", "100000");

            if (TradingPartnerType != TradingPartnerType.Supplier && TradingPartnerType != TradingPartnerType.Employee)
                throw new UserFriendlyException("交易对象只能是供应商，客户或者员工", "100000");

            if (IsAdvanced == true && TradingPartnerType != TradingPartnerType.Supplier)
                throw new UserFriendlyException("预付款的交易对象只能是供应商", "100000");

            if (TradingPartnerType == TradingPartnerType.Supplier && (EmployeeId.HasValue || CustomerId.HasValue))
                throw new UserFriendlyException("交易对象为供应商时，只能填写供应商信息", "100000");

            if (TradingPartnerType == TradingPartnerType.Employee && (SupplierId.HasValue || CustomerId.HasValue))
                throw new UserFriendlyException("交易对象为员工时，只能填写员工信息", "100000");

            if (TradingPartnerType == TradingPartnerType.Customer && (SupplierId.HasValue || EmployeeId.HasValue))
                throw new UserFriendlyException("交易对象为客户时，只能填写客户信息", "100000");
        }

        private void CalculateAmount()
        {
            foreach (var item in Items)
            {
                item.CalculateAmount(ExchangeRate);
            }

            Amount = Items.Sum(x => x.Amount);
            AmountFr = Items.Sum(x => x.AmountFr);
        }
        #endregion
    }

    public class PaymentRequisitionItem : DocumentEntity
    {
        /// <summary>
        /// 应付金额
        /// </summary>
        public decimal? PayableAmountFr {  get; private set; }

        /// <summary>
        /// 应付金额
        /// </summary>
        public decimal? PayableAmount { get; private set; }

        public DocumentType? SourceDocumentType { private set; get; }

        public Guid? SourceDocumentId { private set; get; }

        public Guid? SourceDocumentEntryId { private set; get; }

        public DateTime? DueDate { get; private set; }

        public DateTime? ExpectedPaymentDate {  get; private set; }

        private PaymentRequisitionItem() { }

        public PaymentRequisitionItem(Guid id, DocumentType? sourceDocumentType , Guid? sourceDocumentId, Guid? sourceDocumentEntryId, decimal? payableAmountFr, decimal? payableAmount, decimal requisitionAmountFr, decimal? requisitionAmount, 
            DateTime? dueDate , DateTime? expectedPaymentDate ,  string remark)
        {
            Id = id;

            SourceDocumentType = sourceDocumentType;
            SourceDocumentId = sourceDocumentId;
            SourceDocumentEntryId = sourceDocumentEntryId;

            PayableAmount = payableAmount;
            PayableAmountFr = payableAmountFr;

            AmountFr = requisitionAmountFr;
            Amount = requisitionAmount ?? 0;

            DueDate = dueDate;
            ExpectedPaymentDate = expectedPaymentDate;
            Remark = remark;

            Validate();
        }

        #region
        private void Validate()
        {
            if (SourceDocumentId.HasValue && !SourceDocumentType.HasValue)
                throw new UserFriendlyException("源单类型不能为空", "100000");

            if (!SourceDocumentId.HasValue && SourceDocumentType.HasValue)
                throw new UserFriendlyException("源单不能为空", "100000");

            if (AmountFr <= 0)
                throw new UserFriendlyException("申请金额必须大于0", "100000");

            if (SourceDocumentId.HasValue && (!PayableAmount.HasValue || !PayableAmountFr.HasValue))
                throw new UserFriendlyException("应付金额不能为空", "100000");

            if(!SourceDocumentId.HasValue && (PayableAmount.HasValue || PayableAmountFr.HasValue))
                throw new UserFriendlyException("没有源单单据，不能录入应付金额", "100000");
        }


        public void CalculateAmount(decimal exchangeRate)
        {
            if (Amount == 0)
                Amount = AmountFr * exchangeRate;
        }
        #endregion
    }
}
